home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / WINGs / wslider.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-09  |  12.2 KB  |  556 lines

  1.  
  2.  
  3.  
  4.  
  5. #include "WINGsP.h"
  6.  
  7.  
  8. #undef STRICT_NEXT_BEHAVIOUR
  9.  
  10.  
  11. typedef struct W_Slider {
  12.     W_Class widgetClass;
  13.     WMView *view;
  14.  
  15.     int minValue;
  16.     int maxValue;
  17.     
  18.     int value;
  19.  
  20.     Pixmap knobPixmap;
  21.     WMPixmap *backPixmap;
  22.  
  23.     WMAction *action;
  24.     void *clientData;
  25.  
  26.     int knobThickness;
  27.  
  28.     struct {
  29.     unsigned int continuous:1;
  30.     
  31.     unsigned int vertical:1;
  32.     unsigned int dragging:1;
  33.     } flags;
  34.     
  35. } Slider;
  36.  
  37.  
  38.  
  39.  
  40. static void didResizeSlider();
  41.  
  42.  
  43. W_ViewDelegate _SliderViewDelegate = {
  44.     NULL,
  45.     NULL,
  46.     didResizeSlider,
  47.     NULL,
  48.     NULL
  49. };
  50.  
  51.  
  52.  
  53. static void destroySlider(Slider *sPtr);
  54. static void paintSlider(Slider *sPtr);
  55. static void realizeSlider(Slider *sPtr);
  56.  
  57. static void handleEvents(XEvent *event, void *data);
  58. static void handleActionEvents(XEvent *event, void *data);
  59.  
  60. static void makeKnobPixmap(Slider *sPtr);
  61.  
  62. static void
  63. realizeObserver(void *self, WMNotification *not)
  64. {
  65.     realizeSlider(self);
  66. }
  67.  
  68.  
  69.           
  70. WMSlider*
  71. WMCreateSlider(WMWidget *parent)
  72. {
  73.     Slider *sPtr;
  74.  
  75.     sPtr = wmalloc(sizeof(Slider));
  76.     memset(sPtr, 0, sizeof(Slider));
  77.  
  78.     sPtr->widgetClass = WC_Slider;
  79.     
  80.     sPtr->view = W_CreateView(W_VIEW(parent));
  81.     if (!sPtr->view) {
  82.     wfree(sPtr);
  83.     return NULL;
  84.     }
  85.     sPtr->view->self = sPtr;
  86.  
  87.     sPtr->view->delegate = &_SliderViewDelegate;
  88.  
  89.     WMCreateEventHandler(sPtr->view, ExposureMask|StructureNotifyMask,
  90.              handleEvents, sPtr);
  91.  
  92.  
  93.     WMCreateEventHandler(sPtr->view, ButtonPressMask|ButtonReleaseMask
  94.              |EnterWindowMask|LeaveWindowMask|ButtonMotionMask,
  95.              handleActionEvents, sPtr);
  96.  
  97.     W_ResizeView(sPtr->view, 100, 16);
  98.     sPtr->flags.vertical = 0;
  99.     sPtr->minValue = 0;
  100.     sPtr->maxValue = 100;
  101.     sPtr->value = 50;
  102.  
  103.     sPtr->knobThickness = 20;
  104.  
  105.     sPtr->flags.continuous = 1;
  106.     
  107.     WMAddNotificationObserver(realizeObserver, sPtr, 
  108.                   WMViewRealizedNotification, sPtr->view);
  109.  
  110.     return sPtr;
  111. }
  112.  
  113.  
  114. void
  115. WMSetSliderImage(WMSlider *sPtr, WMPixmap *pixmap)
  116. {
  117.     if (sPtr->backPixmap)
  118.     WMReleasePixmap(sPtr->backPixmap);
  119.  
  120.     sPtr->backPixmap = WMRetainPixmap(pixmap);
  121.     
  122.     if (sPtr->view->flags.mapped) {
  123.     paintSlider(sPtr);
  124.     }
  125. }
  126.  
  127.  
  128. void
  129. WMSetSliderKnobThickness(WMSlider *sPtr, int thickness)
  130. {
  131.     assert(thickness > 0);
  132.  
  133.     sPtr->knobThickness = thickness;
  134.  
  135.     if (sPtr->knobPixmap) {
  136.     makeKnobPixmap(sPtr);
  137.     }
  138.  
  139.     if (sPtr->view->flags.mapped) {
  140.     paintSlider(sPtr);
  141.     }
  142. }
  143.  
  144.  
  145. int
  146. WMGetSliderMinValue(WMSlider *slider)
  147. {
  148.     CHECK_CLASS(slider, WC_Slider);
  149.     
  150.     return slider->minValue;
  151. }
  152.  
  153.  
  154. int
  155. WMGetSliderMaxValue(WMSlider *slider)
  156. {
  157.     CHECK_CLASS(slider, WC_Slider);
  158.     
  159.     return slider->maxValue;
  160. }
  161.  
  162.  
  163. int
  164. WMGetSliderValue(WMSlider *slider)
  165. {
  166.     CHECK_CLASS(slider, WC_Slider);
  167.  
  168.     return slider->value;
  169. }
  170.  
  171.  
  172. void
  173. WMSetSliderMinValue(WMSlider *slider, int value)
  174. {
  175.     CHECK_CLASS(slider, WC_Slider);
  176.     
  177.     slider->minValue = value;
  178.     if (slider->value < value) {
  179.     slider->value = value;
  180.     if (slider->view->flags.mapped)
  181.         paintSlider(slider);
  182.     }
  183. }
  184.  
  185.  
  186. void
  187. WMSetSliderMaxValue(WMSlider *slider, int value)
  188. {
  189.     CHECK_CLASS(slider, WC_Slider);
  190.     
  191.     slider->maxValue = value;
  192.     if (slider->value > value) {
  193.     slider->value = value;
  194.     if (slider->view->flags.mapped)
  195.         paintSlider(slider);
  196.     }
  197. }
  198.  
  199.  
  200. void
  201. WMSetSliderValue(WMSlider *slider, int value)
  202. {
  203.     CHECK_CLASS(slider, WC_Slider);
  204.     
  205.     if (value < slider->minValue)
  206.     slider->value = slider->minValue;
  207.     else if (value > slider->maxValue)
  208.     slider->value = slider->maxValue;
  209.     else
  210.     slider->value = value;
  211.     
  212.     if (slider->view->flags.mapped)
  213.     paintSlider(slider);
  214. }
  215.  
  216.  
  217. void
  218. WMSetSliderContinuous(WMSlider *slider, Bool flag)
  219. {
  220.     CHECK_CLASS(slider, WC_Slider);
  221.     
  222.     slider->flags.continuous = flag;
  223. }
  224.  
  225.  
  226. void
  227. WMSetSliderAction(WMSlider *slider, WMAction *action, void *data)
  228. {
  229.     CHECK_CLASS(slider, WC_Slider);
  230.     
  231.     slider->action = action;
  232.     slider->clientData = data;
  233. }
  234.  
  235.  
  236. static void
  237. makeKnobPixmap(Slider *sPtr)
  238. {
  239.     Pixmap pix;
  240.     WMScreen *scr = sPtr->view->screen;
  241.     int w, h;
  242.     
  243.     if (sPtr->flags.vertical) {
  244.     w = sPtr->view->size.width-2;
  245.     h = sPtr->knobThickness;
  246.     } else {
  247.     w = sPtr->knobThickness;
  248.     h = sPtr->view->size.height-2;
  249.     }
  250.     
  251.     pix = XCreatePixmap(scr->display, sPtr->view->window, w, h, scr->depth);
  252.     XFillRectangle(scr->display, pix, WMColorGC(scr->gray), 0, 0, w, h);
  253.  
  254.     if (sPtr->knobThickness < 10) {
  255.     W_DrawRelief(scr, pix, 0, 0, w, h, WRRaised);
  256.     } else if (sPtr->flags.vertical) {
  257.     XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, 0, h-3);
  258.     XDrawLine(scr->display, pix, WMColorGC(scr->white), 1, 0, 1, h-3);
  259.     XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w-2, 1, w-2, h/2-2);
  260.     XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w-2, h/2, w-2, h-2);
  261.     
  262.     XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, w-2, 0);
  263.     XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 1, h/2-2, w-3, h/2-2);
  264.     XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, h/2-1, w-3, h/2-1);
  265.     
  266.     XDrawLine(scr->display, pix, WMColorGC(scr->black), w-1, 0, w-1, h-2);
  267.     
  268.     XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 0, h-3, w-2, h-3);
  269.     XDrawLine(scr->display, pix, WMColorGC(scr->black), 0, h-2, w-1, h-2);
  270.     XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 0, h-1, w-1,h-1);
  271.     } else {
  272.     XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, w-3, 0);
  273.     
  274.     XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, 0, h-2);
  275.  
  276.     XDrawLine(scr->display, pix, WMColorGC(scr->white), 1, 0, 1, h-3);
  277.     XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w/2-2, 1, w/2-2, h-3);
  278.     XDrawLine(scr->display, pix, WMColorGC(scr->white), w/2-1, 0, w/2-1, h-3);
  279.  
  280.     XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w-3, 0, w-3, h-2);
  281.     XDrawLine(scr->display, pix, WMColorGC(scr->black), w-2, 0, w-2, h-2);
  282.     XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w-1, 0, w-1, h-1);
  283.  
  284.     XDrawLine(scr->display, pix, WMColorGC(scr->black), 1, h-1, w/2+1, h-1);
  285.     XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 1, h-2, w/2-2, h-2);
  286.     XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w/2, h-2, w-3,h-2);
  287.  
  288.     XDrawLine(scr->display, pix, WMColorGC(scr->black), 0, h-1, w-2, h-1);
  289.     }
  290.     
  291.     if (sPtr->knobPixmap)
  292.     XFreePixmap(scr->display, sPtr->knobPixmap);
  293.     sPtr->knobPixmap = pix;
  294. }
  295.  
  296.  
  297. static void
  298. realizeSlider(Slider *sPtr)
  299. {
  300.     W_RealizeView(sPtr->view);
  301.  
  302.     makeKnobPixmap(sPtr);
  303. }
  304.  
  305.  
  306. static void
  307. didResizeSlider(W_ViewDelegate *self, WMView *view)
  308. {
  309.     Slider *sPtr = (Slider*)view->self;
  310.     int width = sPtr->view->size.width;
  311.     int height = sPtr->view->size.height;
  312.  
  313.     assert(width > 0);
  314.     assert(height > 0);
  315.     
  316.     if (width > height) {
  317.     if (sPtr->flags.vertical) {
  318.         sPtr->flags.vertical = 0;
  319.         if (sPtr->view->flags.realized)
  320.         makeKnobPixmap(sPtr);
  321.     }
  322.     } else {
  323.     if (!sPtr->flags.vertical) {
  324.         sPtr->flags.vertical = 1;
  325.         if (sPtr->view->flags.realized)
  326.         makeKnobPixmap(sPtr);
  327.     }
  328.     }
  329. }
  330.  
  331.  
  332.  
  333. static void
  334. paintSlider(Slider *sPtr)
  335. {
  336.     W_Screen *scr = sPtr->view->screen;
  337.     GC bgc;
  338.     GC wgc;
  339.     GC lgc;
  340.     WMSize size = sPtr->view->size;
  341.     int pos;
  342.     Pixmap buffer;
  343.     
  344. #define MINV sPtr->minValue
  345. #define MAXV sPtr->maxValue
  346. #define POSV sPtr->value
  347.     
  348.     bgc = WMColorGC(scr->black);
  349.     wgc = WMColorGC(scr->white);
  350.     lgc = WMColorGC(scr->gray);
  351.  
  352.     buffer = XCreatePixmap(scr->display, sPtr->view->window, 
  353.                size.width, size.height, scr->depth);
  354.  
  355.     if (sPtr->backPixmap) {
  356.     WMSize size = WMGetPixmapSize(sPtr->backPixmap);
  357.  
  358.     XCopyArea(scr->display, WMGetPixmapXID(sPtr->backPixmap), 
  359.           buffer, scr->copyGC, 0, 0, size.width, size.height, 1, 1);
  360.     } else {
  361.     XFillRectangle(scr->display, buffer, lgc, 0, 0, size.width, 
  362.                size.height);
  363.     XFillRectangle(scr->display, buffer, scr->stippleGC, 0, 0, size.width, 
  364.                size.height);
  365.     }
  366.     
  367.     if (sPtr->flags.vertical) {
  368.     pos = (size.height-2-sPtr->knobThickness)*(POSV-MINV)/(MAXV-MINV)+1;
  369.     /* draw knob */
  370.     XCopyArea(scr->display, sPtr->knobPixmap, buffer,
  371.           scr->copyGC, 0, 0, size.width-2, sPtr->knobThickness, 
  372.           1, pos);
  373.     } else {
  374.     pos = (size.width-2-sPtr->knobThickness)*(POSV-MINV)/(MAXV-MINV)+1;
  375.     /* draw knob */
  376.     XCopyArea(scr->display, sPtr->knobPixmap, buffer, 
  377.           scr->copyGC, 0, 0, sPtr->knobThickness, size.height, pos, 1);
  378.     }
  379.  
  380.     XDrawLine(scr->display, buffer, bgc, 0, 0, 0, size.height-1);
  381.     XDrawLine(scr->display, buffer, bgc, 0, 0, size.width, 0);
  382.     
  383.     XDrawLine(scr->display, buffer, wgc, size.width-1, 0, 
  384.           size.width-1, size.height-1);
  385.     XDrawLine(scr->display, buffer, wgc, 0, size.height-1, 
  386.           size.width-1, size.height-1);
  387.  
  388.     XCopyArea(scr->display, buffer, sPtr->view->window, scr->copyGC, 0, 0,
  389.           size.width, size.height, 0, 0);
  390.     XFreePixmap(scr->display, buffer);
  391. }
  392.  
  393.  
  394.  
  395. static void
  396. handleEvents(XEvent *event, void *data)
  397. {
  398.     Slider *sPtr = (Slider*)data;
  399.  
  400.     CHECK_CLASS(data, WC_Slider);
  401.  
  402.  
  403.     switch (event->type) {
  404.      case Expose:
  405.     if (event->xexpose.count!=0)
  406.         break;
  407.     paintSlider(sPtr);
  408.     break;
  409.     
  410.      case DestroyNotify:
  411.     destroySlider(sPtr);
  412.     break;
  413.     
  414.     }
  415. }
  416.  
  417.  
  418. #define DECR_PART    1
  419. #define KNOB_PART    2
  420. #define INCR_PART    3
  421.  
  422. static int
  423. getSliderPart(Slider *sPtr, int x, int y)
  424. {
  425.     int p;
  426.     int pos;
  427.     WMSize size = sPtr->view->size;
  428.     
  429.  
  430.     if (sPtr->flags.vertical) {
  431.     p = y;
  432.     pos = (size.height-2-sPtr->knobThickness)*(POSV-MINV)/(MAXV-MINV);
  433.     if (p < pos)
  434.         return INCR_PART;
  435.     if (p > pos + sPtr->knobThickness)
  436.         return DECR_PART;
  437.     return KNOB_PART;
  438.     } else {
  439.     p = x;
  440.     pos = (size.width-2-sPtr->knobThickness)*(POSV-MINV)/(MAXV-MINV);
  441.     if (p < pos)
  442.         return DECR_PART;
  443.     if (p > pos + sPtr->knobThickness)
  444.         return INCR_PART;
  445.     return KNOB_PART;
  446.     }
  447. }
  448.  
  449.  
  450. static int
  451. valueForMousePoint(Slider *sPtr, int x, int y)
  452. {
  453.     WMSize size = sPtr->view->size;
  454.     int f;
  455.  
  456.     if (sPtr->flags.vertical) {
  457.     f = (y-sPtr->knobThickness/2)*(MAXV-MINV)
  458.         / ((int)size.height-2-sPtr->knobThickness);
  459.     } else {
  460.     f = (x-sPtr->knobThickness/2)*(MAXV-MINV)
  461.         / ((int)size.width-2-sPtr->knobThickness);
  462.     }
  463.  
  464.     f += sPtr->minValue;
  465.     if (f < sPtr->minValue)
  466.     f = sPtr->minValue;
  467.     else if (f > sPtr->maxValue)
  468.     f = sPtr->maxValue;
  469.  
  470.     return f;
  471. }
  472.  
  473.  
  474. static void
  475. handleActionEvents(XEvent *event, void *data)
  476. {
  477.     WMSlider *sPtr = (Slider*)data;
  478.  
  479.     CHECK_CLASS(data, WC_Slider);
  480.  
  481.  
  482.     switch (event->type) {
  483.      case ButtonPress:
  484.     if (getSliderPart(sPtr, event->xbutton.x, event->xbutton.y)==KNOB_PART)
  485.         sPtr->flags.dragging = 1;
  486.     else {
  487. #ifdef STRICT_NEXT_BEHAVIOUR
  488.         sPtr->flags.dragging = 1;
  489.  
  490.         sPtr->value = valueForMousePoint(sPtr, event->xmotion.x,
  491.                          event->xmotion.y);
  492.         paintSlider(sPtr);
  493. #else
  494.         int tmp;
  495.  
  496.         if (event->xbutton.button == Button2) {
  497.         sPtr->flags.dragging = 1;
  498.  
  499.         sPtr->value = valueForMousePoint(sPtr, event->xmotion.x,
  500.                          event->xmotion.y);
  501.         paintSlider(sPtr);
  502.         } else {
  503.         tmp = valueForMousePoint(sPtr, event->xmotion.x,
  504.                      event->xmotion.y);
  505.         if (tmp < sPtr->value)
  506.             tmp = sPtr->value-1;
  507.         else
  508.             tmp = sPtr->value+1;
  509.         WMSetSliderValue(sPtr, tmp);
  510.         }
  511. #endif
  512.  
  513.         if (sPtr->flags.continuous && sPtr->action) {
  514.         (*sPtr->action)(sPtr, sPtr->clientData);
  515.         }
  516.     }
  517.     break;
  518.  
  519.      case ButtonRelease:
  520.     if (!sPtr->flags.continuous && sPtr->action) {
  521.         (*sPtr->action)(sPtr, sPtr->clientData);
  522.     }
  523.     sPtr->flags.dragging = 0;
  524.     break;
  525.  
  526.      case MotionNotify:
  527.     if (sPtr->flags.dragging) {
  528.         sPtr->value = valueForMousePoint(sPtr, event->xmotion.x,
  529.                          event->xmotion.y);
  530.         paintSlider(sPtr);
  531.         
  532.         if (sPtr->flags.continuous && sPtr->action) {
  533.         (*sPtr->action)(sPtr, sPtr->clientData);
  534.         }
  535.     }
  536.     break;
  537.     }
  538. }
  539.  
  540.  
  541.  
  542. static void
  543. destroySlider(Slider *sPtr)
  544. {
  545.     if (sPtr->knobPixmap)
  546.     XFreePixmap(sPtr->view->screen->display, sPtr->knobPixmap);
  547.  
  548.     if (sPtr->backPixmap)
  549.     WMReleasePixmap(sPtr->backPixmap);
  550.  
  551.     WMRemoveNotificationObserver(sPtr);
  552.  
  553.     wfree(sPtr);
  554. }
  555.  
  556.